package com.platform.common.util;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import org.apache.commons.lang.StringUtils;

/**
 * Description: 排序工具类
 */
public class SortUtil {

	/**
	 * 升序
	 * 
	 * @param map
	 * @return
	 */
	public static <K, V> Map<K, V> asc(Map<K, V> map) {
		return asc(map, "");
	}

	/**
	 * 降序
	 * 
	 * @param map
	 * @return
	 */
	public static <K, V> Map<K, V> desc(Map<K, V> map) {
		return desc(map, "");
	}

	/**
	 * 升序
	 * 
	 * @param map
	 * @return
	 */
	public static <K, V> Map<K, V> asc(Map<K, V> map, final String orderFieldName) {
		Map<K, V> sortedMap = new TreeMap<K, V>(new Comparator<K>() {
			public int compare(K o1, K o2) {
				return SortUtil.compare(o1, o2, Order.ASC, orderFieldName);
			}
		});
		sortedMap.putAll(map);
		return sortedMap;
	}

	/**
	 * 降序
	 * 
	 * @param map
	 * @return
	 */
	public static <K, V> Map<K, V> desc(Map<K, V> map, final String orderFieldName) {
		Map<K, V> sortedMap = new TreeMap<K, V>(new Comparator<K>() {
			public int compare(K o1, K o2) {
				return SortUtil.compare(o1, o2, Order.DESC, orderFieldName);
			}
		});
		sortedMap.putAll(map);
		return sortedMap;
	}

	/**
	 * 升序
	 * 
	 * @param set
	 * @return
	 */
	public static <T> Set<T> asc(Set<T> set) {
		return asc(set, "");
	}

	/**
	 * 降序
	 * 
	 * @param set
	 * @return
	 */
	public static <T> Set<T> desc(Set<T> set) {
		return desc(set, "");
	}

	/**
	 * 升序
	 * 
	 * @param set
	 * @return
	 */
	public static <T> Set<T> asc(Set<T> set, final String orderFieldName) {
		Set<T> sortedSet = new TreeSet<T>(new Comparator<T>() {
			public int compare(T o1, T o2) {
				return SortUtil.compare(o1, o2, Order.ASC, orderFieldName);
			}
		});
		sortedSet.addAll(set);
		return sortedSet;
	}

	/**
	 * 降序
	 * 
	 * @param set
	 * @return
	 */
	public static <T> Set<T> desc(Set<T> set, final String orderFieldName) {
		Set<T> sortedSet = new TreeSet<T>(new Comparator<T>() {
			public int compare(T o1, T o2) {
				return SortUtil.compare(o1, o2, Order.DESC, orderFieldName);
			}
		});
		sortedSet.addAll(set);
		return sortedSet;
	}

	/**
	 * 升序
	 * 
	 * @param list
	 * @return
	 */
	public static <T> List<T> asc(List<T> list) {
		return asc(list, "");
	}

	/**
	 * 降序
	 * 
	 * @param list
	 * @return
	 */
	public static <T> List<T> desc(List<T> list) {
		return desc(list, "");
	}

	/**
	 * 升序
	 * 
	 * @param list
	 * @param orderFieldName
	 * @return
	 */
	public static <T> List<T> asc(List<T> list, final String orderFieldName) {
		Collections.sort(list, new Comparator<T>() {
			public int compare(T o1, T o2) {
				return SortUtil.compare(o1, o2, Order.ASC, orderFieldName);
			}
		});
		return list;
	}

	/**
	 * 降序
	 * 
	 * @param list
	 * @param orderFieldName
	 * @return
	 */
	public static <T> List<T> desc(List<T> list, final String orderFieldName) {
		Collections.sort(list, new Comparator<T>() {
			public int compare(T o1, T o2) {
				return SortUtil.compare(o1, o2, Order.DESC, orderFieldName);
			}
		});
		return list;
	}

	/**
	 * 
	 * @param o1
	 * @param o2
	 * @param order
	 * @return
	 */
	public static int compare(Object o1, Object o2, Order order) {
		return compare(o1, o2, order, "");
	}

	/**
	 * 排序
	 * 
	 * @param o1
	 * @param o2
	 * @param order
	 * @param orderFieldName
	 * @return
	 */
	public static int compare(Object o1, Object o2, Order order, String orderFieldName) {
		int c = SortUtil.compare(o1, o2, orderFieldName);
		// System.out.println(o1 + "：" + o2 + ",order:" + c);
		if (order == Order.ASC)
			return c > 0 ? 1 : (c < 0 ? -1 : c);
		else
			return c > 0 ? -1 : (c < 0 ? 1 : c);
	}

	/**
	 * 
	 * @param o1
	 * @param o2
	 * @return
	 */
	public static int compare(Object o1, Object o2) {
		return compare(o1, o2, Order.ASC);
	}

	public static int compare(Object o1, Object o2, String orderFieldName) {
		try {
			if (o1 != null && o2 == null)
				return 1;
			else if (o1 == null && o2 != null)
				return -1;

			if (o1 instanceof Integer) {
				return Integer.compare(Integer.parseInt(String.valueOf(o1)), Integer.parseInt(String.valueOf(o2)));
			} else if (o1 instanceof String) {
				return String.valueOf(o1).compareTo(String.valueOf(o2));
			} else if (o1 instanceof Double) {
				return Double.compare(Double.parseDouble(String.valueOf(o1)), Double.parseDouble(String.valueOf(o2)));
			} else if (o1 instanceof Float) {
				return Float.compare(Float.parseFloat(String.valueOf(o1)), Float.parseFloat(String.valueOf(o2)));
			} else if (o1 instanceof Long) {
				return Long.compare(Long.parseLong(String.valueOf(o1)), Long.parseLong(String.valueOf(o2)));
			} else if (o1 instanceof Date) {
				return DateUtil.compare((Date) o1, (Date) o2);
			} else if (o1 instanceof Map && !StringUtils.isEmpty(orderFieldName)) {
				Object v1 = ((Map) o1).get(orderFieldName);
				Object v2 = ((Map) o2).get(orderFieldName);
				return compare(v1, v2, orderFieldName);
			} else if (o1.getClass().isEnum()) {
				return String.valueOf(o1).compareTo(String.valueOf(o2));
			} else if (o1.getClass().isMemberClass()) {
				return compareClass(o1, o2, orderFieldName);
			} else if (o1 instanceof Class) {
				return compareClass(o1, o2, orderFieldName);
			}
			return compareClass(o1, o2, orderFieldName);
		} catch (Exception ex) {
			ex.printStackTrace();
			throw new IllegalArgumentException("Could not recognize the object");
		}
	}

	/**
	 * 
	 * @param c1
	 * @param c2
	 * @param orderFieldName
	 * @return
	 */
	private static int compareClass(Object o1, Object o2, String orderFieldName) {
		try {
			if (!StringUtils.isEmpty(orderFieldName)) {
				Class<?> c1 = o1.getClass();
				Class<?> c2 = o2.getClass();
				String m = orderFieldName.substring(0, 1).toUpperCase() + orderFieldName.substring(1);
				Method method1 = c1.getMethod(String.format("get%s", m));
				Method method2 = c2.getMethod(String.format("get%s", m));
				if (method1 != null && method2 != null) {
					Object v1 = method1.invoke(o1);
					Object v2 = method2.invoke(o2);
					return compare(v1, v2, orderFieldName);
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return Integer.compare(o1.hashCode(), o2.hashCode());
	}

	enum Order {
		ASC, DESC
	}

}
